// 多线程


/* 该代码用来测验基本函数的用法 */
// /*
// NAME
//        pthread_create - create a new thread

// SYNOPSIS
//        #include <pthread.h>

//        int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
//                           void *(*start_routine) (void *), void *arg);

//        Compile and link with -pthread.
// */

// /*
// NAME
//        pthread_join - join with a terminated thread

// SYNOPSIS
//        #include <pthread.h>

//        int pthread_join(pthread_t thread, void **retval);

//        Compile and link with -pthread.
// */

// /*
// "Segmentation fault (core dumped)" 是一个常见的运行时错误，通常表示你的程序试图访问未分配给它的内存或者非法内存区域。这种错误通常是由以下几种情况引起的：

// 空指针解引用：即对空指针进行了解引用操作，例如试图访问一个未初始化或者被释放的指针。

// 访问越界：例如访问了数组或者其他数据结构的越界位置，导致访问了不属于该数组或数据结构的内存区域。

// 使用已经释放的内存：尝试使用已经通过 delete 或 free 释放的内存。

// 栈溢出：函数调用或者递归调用导致栈空间耗尽。
// */

// #include <iostream>
// #include <pthread.h>
// #include <unistd.h> // sleep

// using namespace std;

// void* threadRoutine(void* args)
// {
//     int i = 0;
//     int* arr = new int[10];
//     while (true)
//     {
//         cout << "I am new thread: " << (char*)args << endl;
//         sleep(1);

//         arr[i] = i;
//         i++;
//         if (i == 10)
//             break;
//     }
//     cout << "new thread quit!" << endl;

//     // 实际上返回的是int* 类型
//     return (void*)arr;
// }

// int main()
// {
//     // 创建一个新线程
//     pthread_t tid; // 线程id

//     // 第三个参数会当作第二个函数指针的参数传入，在创建好新线程后，会自动调用第三个参数
//     pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");

//     // 等待新线程退出
//     // 线程的函数特点：1、以 pthread_ 开头 2、成功返回0，失败返回错误码
    
//     // 第二个参数带回新线程的返回值
//     // void* ret = nullptr;
//     int* ret = nullptr;
//     // 用nullptr比NULL好，因为nullptr在C++中就是一个指针，而NULL实际上是一个整型
//     pthread_join(tid, (void**)&ret);
//     // 这种写法是正确的，因为&ret指向的是int*类型，void**指向的是void*类型，都是指向一级指针

//     // pthread_join(tid, (void**)ret);
//     // 这种写法是错误的，因为ret指向的是int类型，但是void**指向的是void*类型
//     // 会报运行时错误，Segmentation fault (core dumped)
//     // 后续我试验：对int类型解引用，会报同样的错误，说明这种解释是正确的
//     /*
//       int a = 0;
//       cout << *((int*)a) << endl;
//     */ 
//     // 但是数字可以强制类型转换为任何类型

//     cout << "main thread wait new thread success!" << endl;

//     for (int i = 0; i < 10; i++)
//     {
//         cout << (long long)ret[i] << " ";
//         // 转化为ll的原因：因为Linux是64位机器，指针大小位8字节，但是int只有四字节，会截断
//     }

//     delete[] ret;
//     cout << endl;
// }


/* 测试优化后的g++ -O3选项在面对全局变量时，会不会根据线程的不同而结果不同--------------> 不会 */

// #include <iostream>
// #include <pthread.h>
// #include <unistd.h> // sleep

// using namespace std;

// __thread int g_val = 0;
// // 加__thread前，两个线程打印出来的g_val和&g_val的值相同
// // 加__thread后，两个数据不同，只有新线程的g_val的值在变

// void* threadRoutine(void* args)
// {
//     while (true)
//     {
//         cout << (char*)args << "g_val = " << g_val << " &: " << &g_val << endl;
//         // g_val++;
//         // 即使不更改g_val的值，两者的g_val的地址也不一样
//         sleep(1);
//     }
// }

// int main()
// {
//     // 创建一个新线程
//     pthread_t tid; // 线程id

//     // 第三个参数会当作第二个函数指针的参数传入，在创建好新线程后，会自动调用第三个参数
//     pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");

//     while (true)
//     {
//         cout << "main thread" << "g_val = " << g_val << " &: " << &g_val << endl;
//         sleep(1);
//     }

//     cout << endl;
// }


/* 测试在新线程创建子进程后会有几个线程，看新线程是存在 还是 被退出 ------------> 存在 */
/* 测试在主线程创建子进程后会有几个线程，看新线程是存在 还是 被退出 ------------> 存在 */
/* 若是使用execl，则直接替换了整个进程 */

/*
while :; do ps -aL | head -1 && ps -aL | grep "mythread" | grep -v "grep"; sleep 1; done
查看运行的线程信息，也可通过ctrl + r的选项搜索
*/

#include <iostream>
#include <pthread.h>
#include <unistd.h> // sleep

using namespace std;

void* threadRoutine(void* args)
{
    // fork();
    while (true)
    {
        cout << (char*)args << endl;
        sleep(1);
    }
}

int main()
{
    // 创建一个新线程
    pthread_t tid; // 线程id

    // 第三个参数会当作第二个函数指针的参数传入，在创建好新线程后，会自动调用第三个参数
    pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");
    // fork();
    while (true)
    {
        cout << "main thread" << endl;
        sleep(1);
    }

    cout << endl;
    return 0;
}